package com.momoc.mrpc.rpc.client;

import com.alibaba.nacos.api.naming.pojo.Instance;
import com.momoc.mrpc.protocol.MRpcProtocolCodec;
import com.momoc.mrpc.register.RegisterContext;
import com.momoc.mrpc.register.definition.MRpcRegDefinition;
import com.momoc.mrpc.rpc.handler.MRpcResponseHandler;
import com.momoc.mrpc.rpc.init.Start;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * @author momoc
 * @version 1.0
 * @className ClientStart
 * @description
 * @date 2022/7/26 11:07 上午
 */
@Component
public class ClientContext implements ApplicationListener {
    Map<String, Channel> channelMap = new ConcurrentHashMap<>();
    NioEventLoopGroup group = new NioEventLoopGroup();

    @Value("${spring.application.name:mrpc}")
    String applicationName;


    /**
     * 打开一个连接
     * @param ip
     * @param port 服务启动netty的端口
     */
    public  Channel doOpen(String ip, Integer port) throws InterruptedException {
        if (channelMap.containsKey(ip)){
            return channelMap.get(ip + port);
        }
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group);
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(65552, 14,4,0,0));
                ch.pipeline().addLast(new MRpcProtocolCodec());
                ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));


                ch.pipeline().addLast(new MRpcResponseHandler());
            }
        });
        Channel channel = bootstrap.connect(ip, port).sync().channel();
        channel.closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                group.shutdownGracefully();
            }
        });
        channelMap.put(ip + port, channel);
        return channel;
    }

    Random random = new Random();
    /**
     * 返回在线服务
     * @param className
     * @return
     */
    public List<Instance> getOnlineServerByClassName(String className){
        //获取接口映射信息
        MRpcRegDefinition mRpcRegDefinition = RegisterContext.getRpcNameServiceMap().get(className);
        String implClassName = mRpcRegDefinition.getInterfaceClassName();
        //获取注册的接口
        Map<String, List<String>> className2Service = RegisterContext.getClassName2Service();
        //获取该注册接口的服务信息
        List<String> serverList = className2Service.get(implClassName);

        List<Instance> onlineChooseServer = new ArrayList<>();

        if (null == serverList || serverList.size() == 0){
            throw new RuntimeException("没有可用的服务：{}" + className);
        }
        //远程忽略本机
        for (String server : serverList) {
            for (Instance instance : RegisterContext.getOnlineServer()) {
                if (server.equals(applicationName)){
                    continue;
                }
                Map<String, String> metadata = instance.getMetadata();
                String service = metadata.get("server.name");
                if (server.equals(service)){
                    onlineChooseServer.add(instance);
                }
            }
        }
        if (onlineChooseServer.size() == 0){
            throw new RuntimeException("没有可用的服务：" + className);
        }
        return onlineChooseServer;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {

    }
}
